#ifndef Algebra_sgPetsc_h
#define Algebra_sgPetsc_h

#include "AlgebraModule.h"
#include "MpiEnvironment.h"

#include "LinearSolver.h"

SG_NAMESPACE_OPEN

namespace Algebra
{
    /**
     * @brief Setup PETSc environment.
     *
     * @author nene
     * @date December, 2024.
     */
    class ALGEBRA_EXPORT PetscEnvironment : public MpiEnvironment
    {
      public:
        PetscEnvironment (int argc, char** argv);
        ~PetscEnvironment ();

        /// Return true if PETSc has been initialized.
        bool initialized () override;

        /// Return true if PETSc has been finalized.
        bool finalized () override;
    };

    /**
     * @brief Wrap PETSc KSP sparse Linear Solver.
     *
     * KSP, the interface to the preconditioners, Krylov subspace methods
     * and direct linear solvers of PETSc.
     *
     * @see https://petsc.org/release/
     *
     * @author nene
     * @date Augst, 2024.
     */
    template <typename TDataType>
    class ALGEBRA_EXPORT TPetscKsp : public TLinearSolver<TDataType>
    {
      public:
        ///@name Type Definitions
        ///@{
        typedef /*typename*/ TDataType                 DataType;
        typedef /*typename*/ Vector_t<TDataType>       VectorType;
        typedef /*typename*/ Matrix_t<TDataType>       MatrixType;
        typedef /*typename*/ SparseMatrix_t<TDataType> SparseMatrixType;
        ///@}

        TPetscKsp ();
        ~TPetscKsp () override;

        const char* getClassName () override;

        /// perform a numeric factorization of the given sparse matrix.
        /// @note KEEP THE MATRIX ALIVE DURING THE WHOLE SOLVING PROCESS.
        void compute (const SparseMatrixType& matrix) override;

        /// evaluate the solution x of Ax=b using the current decomposition of A.
        void solve (const VectorType& b, VectorType& x) const override;

        /// Computes the inverse of square matrix `b` (must be invertible) and stores it in `x` using direct solvers
        void slove (const SparseMatrixType& b, SparseMatrixType& x) const override;

        /// report whether previous computation was successful.
        Info_t info () const override;

    private:
        /// take Adapter Pattern to hide the underlying details.
        struct PetscKspPrivate* d = nullptr;
    };

    // // Enforce the explicit instantiations to hide the underlying implementation.
    // template class ALGEBRA_EXPORT TPetscKsp<Real_t>;
    // template class ALGEBRA_EXPORT TPetscKsp<Complex_t>;

}  // namespace Algebra

SG_NAMESPACE_CLOSE

#endif  // Algebra_sgPetsc_h